﻿using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExpressionEngine
{
    internal abstract class BaseAggregateFunction
    {
        List<BaseAggregateState> _states = new List<BaseAggregateState>();

        public abstract string Name { get; }
        
        public void LoadEntries(string expression)
        {
            foreach (string entry in FindEntries(expression))
                _states.Add(CreateAggregateInstance(entry));
        }

        protected  abstract BaseAggregateState CreateAggregateInstance(string entry);

        public void Reset()
        {
            _states.ForEach(e => e.Reset());
        }

        public void RowChanged(IValueProvider valueProvider)
        {
            _states.ForEach(e => e.RowChanged(valueProvider));
        }

        public string ApplyEntries(string expression)
        {
            foreach (BaseAggregateState instance in _states)
            {
                int startsFrom = expression.IndexOf(instance.OriginalEntry);
                expression = expression.Remove(startsFrom, instance.OriginalEntry.Length);
                expression = expression.Insert(startsFrom, instance.GetResult().ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat));
            }
            return expression;
        }

        private string[] FindEntries(string expression)
        {
            List<string> aggregates = new List<string>();
            for (int i = 0; i < expression.Length; i++)
            {
                char ch = expression[i];
                if (ch == Name.First())
                {
                    StringBuilder builder = new StringBuilder();
                    builder.Append(ch);
                    int j = i + 1;
                    int openedBrace = 0;
                    for (; j < expression.Length; j++)
                    {
                        if (Name.Length > j - i)
                        {
                            if (expression[j] == Name[j - i])
                                builder.Append(expression[j]);
                            else
                                break;
                        }
                        else if (expression[j] == ' ')
                            builder.Append(expression[j]);
                        else if (expression[j] == '(')
                        {
                            builder.Append(expression[j]);
                            openedBrace++;
                        }
                        else if (expression[j] == ')')
                        {
                            openedBrace--;
                            builder.Append(expression[j]);
                            if (openedBrace == 0)
                               break;
                        }
                        else
                        {
                            builder.Append(expression[j]);
                        }
                    }

                    string aggregateExpresion = builder.ToString();

                    if (aggregateExpresion.EndsWith(")"))
                    {
                        aggregates.Add(aggregateExpresion);
                        i = j;
                    }
                }
            }
            return aggregates.ToArray();
        }
    }
}
